home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Internet Standards
/
CD1.mdf
/
winsock
/
hacker
/
93-11
/
000003_paul@atlas.dev.abccomp.oz.au_Tue Nov 23 07:45:44 1993.msg
< prev
next >
Wrap
Internet Message Format
|
1993-11-29
|
12KB
Received: from usage.csd.unsw.OZ.AU by SunSITE.Unc.EDU (5.65c+IDA/FvK-1.06) with SMTP
id AA23361; Mon, 22 Nov 1993 22:40:56 -0500
Received: by usage.csd.unsw.OZ.AU id AA04547
(5.65c/IDA-1.4.4 for winsock-hackers%sunsite.unc.edu); Tue, 23 Nov 1993 14:40:59 +1100
Received: by atlas (4.1/1.35)
id AA22280; Tue, 23 Nov 93 12:45:44 EST
Message-Id: <9311230145.AA22280@atlas>
From: paul@atlas.abccomp.oz.au
Date: Tue, 23 Nov 1993 12:45:44 -0500
X-Mailer: Mail User's Shell (7.2.2 4/12/91)
To: winsock-hackers@sunsite.unc.edu
Subject: accepting new connections in the presence of aborted ones.
I'm running into problems with a WSAT script, that seems to be assuming
different behaviour to my assumptions. Please imagine these two machines
execute the following pseudo-calls in time order increasing down the list -
calls side-by-side are synchronisation points:
Machine 1 Machine 2
s=socket s = socket
bind(s, cli_addr) bind(s, servaddr)
listen(s,5)
connect(s, servaddr) s2=accept(s)
{ data transfer - after a while,
{ connection is reset for some reason }
{ calls on both side return WSAECONNRESET/WSAECONNABORTED }
closesocket(s)
s2 = socket
bind(s2, cli_addr)
connect(s2, srv_addr)...(1)
closesocket(s2)
Because the connection was reset, Machine 1 can bind() immediately
to the same source address/port it had before, and tries to connect to the
same server address/port as before. Because Machine 2 has not yet closed the
socket, the incoming SYN matches the aborted connection. Should machine
2 fail the connection attempt, returnig RST, or create the new connection
in the listening queue? I've always assuemd that an incoming segment which
exactly matches both addresses and ports is associated with an existing
connection if possible and a listening socket if not. At least one
WSAT script seems to assume multiple times that the second connect()
in the sequence above should succeed.
Any thoughts from the protocol and BSD experts out there?
--
Paul Brooks |paul@abccomp.oz.au |Emerging Standard:
TurboSoft Pty Ltd |pwb@newt.phys.unsw.edu.au| one that has not yet
579 Harris St., Ultimo | | been superseded.
Sydney Australia 2007 |ph: +61 2 281 3155 |
From paul@atlas.dev.abccomp.oz.au Tue Nov 23 07:26:00 1993
Received: from usage.csd.unsw.OZ.AU by SunSITE.Unc.EDU (5.65c+IDA/FvK-1.06) with SMTP
id AA23395; Mon, 22 Nov 1993 22:41:19 -0500
Received: by usage.csd.unsw.OZ.AU id AA04551
(5.65c/IDA-1.4.4 for winsock-hackers%sunsite.unc.edu); Tue, 23 Nov 1993 14:41:00 +1100
Received: by atlas (4.1/1.35)
id AA22259; Tue, 23 Nov 93 12:26:00 EST
Message-Id: <9311230126.AA22259@atlas>
From: paul@atlas.abccomp.oz.au
Date: Tue, 23 Nov 1993 12:26:00 -0500
X-Mailer: Mail User's Shell (7.2.2 4/12/91)
To: rcq@ftp.com, Multiple recipients of list <winsock-hackers@sunsite.unc.edu>
Subject: Re: non-blocking lingering close
Thus expounded Bob Quinn on Nov 22, 9:15am:
/--------------------
|Hello Paul!
|
|> I've been looking at using non-blocking calls, but emulating the behaviour
|> of a blocking close, and have determined there is no real way to
|> do so given the 1.1 interface spec. A "blocking graceful close" is when
|> closesocket is called on a socket with a non-zero linger time, and it
|> should block, waiting for all the buffered outgoing data to be sent and
|> acknowledged before returning.
|
|Hmm, I think your premise needs further examination. :-)
|To restate what I believe you are saying, you don't see any
|way to avoid the possibility of closesocket() blocking. Is
|that correct?
Not entirely. I'm fully aware of the semantics on blocking, non-blocking and
hard closes and the various combinations of linger settings.
What I want to do is emulate the semantics of a lingering blocking graceful
closesocket(), without actually blocking inside the implementation. I want
to trigger the sending of the FIN in a non-blocking manner, then periodically
check for when the connection has been fully gracefully closed, without
causing the underlying implementation to block at any time.
|I don't see any problem in the specification. It's not prominent,
|but page 12 of the spec does say closesocket() "only blocks if
|SO_LINGER is set." So by default, closesocket() should return
|immediately and a graceful close should occur in the background.
Thats right, but then the resourses attache to that socket are not free'ed
for some arbitrary time. In particular, its not possible to bind a socket
to the same address/port immediately after this form of "background"
closesocket without setting SO_REUSEADDR, as there is no way to tell when
the connection has been closed, or even if the FIN has reached the
remote host yet or not.
I want to be able to do:
closesocket_equivalent(s1)
s2=socket()
bind(s2,same_port_as_s1),
WITHOUT using the blocking closesocket() by setting a struct linger to
{1,something != 0}.
|> The problem is that there is currently no way to determine if there
|> is still buffered data waiting to be written. Ioctlsocket() has the FIONREAD
|> parameter, to return an indication of data waiting to be read, but there is
|> no corresponding FIONWRITE parameter to determine if buffered data is still
|> waiting to be sent to the remote host, or has not been acknowledged.
|>
|> What are people's thoughts on emulating a lingering close, and whether
|> a new ioctlsocket() parameter could be defined for version 2.0.
|
|Not a good idea. Our stack, for one, does not have a problem with
|closes (blocking or not), but we *would* have a problem providing
|ioctlsocket() FIONWRITE. It's a violation of the API, since it
|reaches into the stack and (in effect) tells you what TCP data has
|not been acknowledged yet. It begs for abuse.
"violation of the API"? APIs are defined to be what is found to be useful,
and/or in this case largely compatible with BSD code. APIs aren't violated,
they are defined.
How does knowing how long the retransmission buffer is currently beg for abuse?
How is this more abuse than being able to find out how many bytes are waiting
to be read, before the recv() call? Please clarify your thoughts on this
"abuse.". I thought proposing something like FIONWRITE was pleasing, if only on
the grounds of symmetry!.
|If you want to avoid a blocking close, and you don't trust the
|default non-blocking close, there is another option for you. You
|can do a shutdown() how==1, which sends a TCP <FIN> *AFTER* all
|the buffered data is sent and acknowledged (in effect a <FIN> says
|"I'm done sending data"). Then you should do recv's (non-blocking
|and/or with the MSG_PEEK flag set). When recv() returns 0 the
|graceful close is complete, and it's safe to call closesocket().
Well, if recv() returns anything else except 0 or WSAEWOULDBLOCK the connection
has to be reset anyway, just like it does now if closesocket() is called
and the receive buffer still contains data.
Your proposal doesn't work in general, because the outgoing and incoming data
streams are essentially independent. Its quite posible for the remote end
to close its end, sending me a FIN, before it has read and acknowledged all
the outgoing data in my buffer. Recv() returning zero doesn't tell me diddly
about whether it has received all my data or not - you are assuming the only
reason it would close is because it has received my FIN, which is not a valid
assumption.
Do people bother with TIMEWAIT state, and disallowing bind()s for the port
during TIMEWAIT?
Am I correct that a closesocket() with linger set on (for a long time)
should block until the socket exits TIMEWAIT (if it is the first
FIN sender)?
I decided to use a non-blocking graceful closesocket, let the socket be closed
in the background, and loosely loop trying to bind a new socket to the
same address until it succeeds. I'm not convinved all the error codes and
conditions are covered though.
Anybody else with a solution?
--
Paul Brooks |paul@abccomp.oz.au |Emerging Standard:
TurboSoft Pty Ltd |pwb@newt.phys.unsw.edu.au| one that has not yet
579 Harris St., Ultimo | | been superseded.
Sydney Australia 2007 |ph: +61 2 281 3155 |
From rcq@ftp.com Tue Nov 23 07:23:21 1993
Received: from ftp.com by SunSITE.Unc.EDU (5.65c+IDA/FvK-1.06) with SMTP
id AB23261; Tue, 23 Nov 1993 13:32:23 -0500
Received: from rcq.oysters.ftp.com by ftp.com via PCMAIL with DMSP
id AA27251; Tue, 23 Nov 93 12:23:21 -0500
Date: Tue, 23 Nov 93 12:23:21 -0500
Message-Id: <9311231723.AA27251@ftp.com>
To: paul@atlas.abccomp.oz.au
Subject: Re: non-blocking lingering close
From: rcq@ftp.com (Bob Quinn)
Reply-To: rcq@ftp.com
Cc: Multiple recipients of list <winsock-hackers@sunsite.unc.edu>
Sender: rcq@ftp.com
Repository: babyoil.ftp.com
Originating-Client: oysters.ftp.com
Hi Paul!
> "violation of the API"? APIs are defined to be what is found to be useful,
> and/or in this case largely compatible with BSD code. APIs aren't violated,
> they are defined.
One of the great advantages of the Windows Sockets API is that
it hides low-level details. APIs are indeed defined to be useful,
but simplicity has great benefits. Exposing low-level details
complicates an API. If its unnecessary, it's a violation.
> How does knowing how long the retransmission buffer is currently beg for abuse?
> How is this more abuse than being able to find out how many bytes are waiting
> to be read, before the recv() call? Please clarify your thoughts on this
> "abuse.".
Detecting incoming data with FIONREAD is very different than
detecting incoming acknowledgments with FIONWRITE. Application
developers would get a false sense of security knowing what data
has been acknowledged, assuming that is the (only) data received
by the other end. If the connection fails, the sender may not
see an acknowledgment for data the other end received.
> Your proposal doesn't work in general, because the outgoing and incoming data
> streams are essentially independent. Its quite posible for the remote end
> to close its end, sending me a FIN, before it has read and acknowledged all
> the outgoing data in my buffer.
One side initiates the close of a TCP socket, not both. If you
have called shutdown(how=1), it's valid to expect recv()=0 to
indicate the completion of a graceful close. Otherwise you have
a seriously broken client/server pair.
> Do people bother with TIMEWAIT state, and disallowing bind()s for the port
> during TIMEWAIT?
Yes. :)
> Am I correct that a closesocket() with linger set on (for a long time)
> should block until the socket exits TIMEWAIT (if it is the first
> FIN sender)?
No. And it doesn't matter what the timeout length is. After
initiating the close, a blocking closesocket() returns immediately
after it receives the TCP <ACK><FIN>. In other words, closesocket()
returns at the point the TCP connection enters the TIMEWAIT state.
The socket is invalid after the return from closesocket(). But if
it just completed a graceful close (that it initiated), the TCP
connection still has some life to it. It can send another <ACK>
if the other side missed the first one and sends another <FIN>.
The port used cannot be bound by another socket until this TIMEWAIT
state expires.
> I decided to use a non-blocking graceful closesocket, let the socket be closed
> in the background, and loosely loop trying to bind a new socket to the
> same address until it succeeds. I'm not convinved all the error codes and
> conditions are covered though.
That is a valid strategy, too.
Regards,
--
Bob Quinn rcq@ftp.com
FTP Software, Inc. No. Andover, MA